#include "request_data.h"

#include <sys/epoll.h>
#include <unistd.h>
#include <sys/time.h>
#include <unordered_map>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <queue>
#include <string.h>
#include <iostream>
#include "global_env.h"


using namespace std;

pthread_mutex_t MimeType::lock = PTHREAD_MUTEX_INITIALIZER;
std::unordered_map <std::string, std::string> MimeType::mime;

std::string MimeType::getMime(const std::string &suffix) {
    if (mime.size() == 0) {
        pthread_mutex_lock(&lock);
        if (mime.size() == 0) {
            mime[".html"] = "text/html";
            mime[".avi"] = "video/x-msvideo";
            mime[".bmp"] = "image/bmp";
            mime[".c"] = "text/plain";
            mime[".doc"] = "application/msword";
            mime[".gif"] = "image/gif";
            mime[".gz"] = "application/x-gzip";
            mime[".htm"] = "text/html";
            mime[".ico"] = "application/x-ico";
            mime[".jpg"] = "image/jpeg";
            mime[".png"] = "image/png";
            mime[".txt"] = "text/plain";
            mime[".mp3"] = "audio/mp3";
            mime["default"] = "text/html";
        }
        pthread_mutex_unlock(&lock);
    }
    if (mime.find(suffix) == mime.end())
        return mime["default"];
    else
        return mime[suffix];
}

// RequestData::RequestData(EventLoop* loop) :
//         loop_(loop),
//         fd_(-1),
//         channel_(new Channel(loop)),
//         nowReadPos_(0),
//         state_(STATE_PARSE_URI),
//         hState_(H_START),
//         keepAlive_(false),
//         againTimes_(0),
// {
//     channel_->SetReadCallBack(std::bind(&RequestData::HandleRead, this));
//     channel_->SetWriteCallBack(std::bind(&RequestData::HandleWrite, this));
//     std::cout << "requestData constructed by 1" << endl;
// }

RequestData::RequestData(EventLoop* loop, int fd) :
        loop_(loop),
        fd_(fd),
        channel_(new Channel(loop, fd)),
        nowReadPos_(0),
        state_(STATE_PARSE_URI),
        hState_(H_START),
        keepAlive_(false),
        againTimes_(0)
{
    channel_->SetReadCallBack(std::bind(&RequestData::HandleRead, this));
    channel_->SetWriteCallBack(std::bind(&RequestData::HandleWrite, this));
    std::cout << "requestData constructed by 2" << endl;
}


RequestData::~RequestData() 
{
    // SeperateTimer();
    close(fd_);
    cout << "~requestData()" << endl;
}

void RequestData::ConnectionEstablished()
{
    loop_->AssertInLoopThread();
    // channel_->tie(shared_from_this());
    channel_->EnableReading();
}

// void RequestData::HandleClose(){
//     auto& epoll = Epoll::Instance();
//     epoll.EpollDel(fd_, shared_from_this(), EPOLLIN | EPOLLET | EPOLLONESHOT);
// }

// void RequestData::SetTimer(std::shared_ptr<MyTimer> _timer) {
//     timer_ = _timer;
// }

void RequestData::Reset() {
    againTimes_ = 0;
    content_.clear();
    fileName_.clear();
    nowReadPos_ = 0;
    state_ = STATE_PARSE_URI;
    hState_ = H_START;
    headers_.clear();
    keepAlive_ = false;
    SeperateTimer();
}


void RequestData::HandleRead()
{
    do{
    int read_num = readn(fd_, inBuffer_);
    if (read_num < 0 || read_num ==0){
        interError_ = true;
        break;
    }

    if (state_ == STATE_PARSE_URI){
        int flag = ParseURI();
        if (flag == PARSE_URI_AGAIN){
            break;
        }
        if (flag == PARSE_URI_ERROR){
            interError_ = true;
            break;
        }
        state_ = STATE_PARSE_HEADERS;
    }

    if (state_ == STATE_PARSE_HEADERS){
        int flag = this->ParseHeaders();
        if (flag == PARSE_HEADER_AGAIN){
            break;
        }
        if (flag == PARSE_HEADER_ERROR){
            interError_ = true;
            break;
        }

        if(method_ == METHOD_POST){
            state_ = STATE_RECV_BODY;
        }else{
            state_ = STATE_ANALYSIS;
        }

    }

    if (state_ == STATE_RECV_BODY){
        int content_length = -1;

        if (headers_.find("Content-length") == headers_.end()){
            interError_ = true;
            break;
        }

        if (inBuffer_.size() < content_length){
            break;
        }

        content_length = stoi(headers_["Content-length"]);
        state_ = STATE_ANALYSIS;
    }

    if (state_ == STATE_ANALYSIS){
        int flag = this->AnalysisRequest();
        if (flag != ANALYSIS_SUCCESS){
            interError_ = true;
            break;
        }
        state_ = STATE_FINISH;
    }
    } while (false);
}

void RequestData::HandleWrite()
{
    if (interError_){
        return;
    }

    if (writen(fd_, outBuffer_) < 0){
        interError_ = true;
        return;
    }
}

// void RequestData::HandleConn()
// {
//     if(interError_){
//         HandleError(fd_, 404, "Not Found!");
//         return;
//     }

//     if (keepAlive_){
//         Reset();
//         AddTimer();

//         auto& epoll = Epoll::Instance();
//         epoll.EpollMod(fd_, shared_from_this(), EPOLLIN | EPOLLET | EPOLLONESHOT);
//         return;
//     }

//     // 短连接 马上释放
//     delete this;
//     return;
// }

// void RequestData::SeperateTimer(){
//     auto timer = timer_.lock();
//     if(timer){
//         // requestData的引用计数减1
//         timer->SetDeleted();
//     }
//     timer_.reset();
// }

// void RequestData::AddTimer(){
//     auto& timerManager = TimerManager::Instance();

//     std::shared_ptr<MyTimer> timer = make_shared<MyTimer>(shared_from_this(), TIME_OUT);
//     timerManager.InsertTimer(timer);
// }


int RequestData::ParseURI() {
    string &str = content_;

    // 读到完整的请求行再开始解析请求
    int pos = str.find('\r', nowReadPos_); 
    if (pos < 0) {
        return PARSE_URI_AGAIN;
    }

    // 去掉请求行所占的空间，节省空间
    string request_line = str.substr(0, pos);
    if (str.size() > pos + 1){
        str = str.substr(pos + 1); 
    }else{
        str.clear();
    }

    // Method
    method_ = METHOD_INVALID;
    int get_pos = request_line.find("GET");
    int post_pos = request_line.find("POST");

    if (get_pos<0 && post_pos <0){
        return PARSE_URI_ERROR;
    }
    if (get_pos){
        method_ = METHOD_GET;
        pos = get_pos;
    }
    if (post_pos){
        method_ = METHOD_POST;
        pos = post_pos;
    }

    // fileName
    pos = request_line.find("/", pos);
    if (pos < 0) {
        return PARSE_URI_ERROR;
    } 

    int _pos = request_line.find(' ', pos);
    if (_pos < 0){
        return PARSE_URI_ERROR;
    }

    if (_pos - pos > 1) {
        fileName_ = request_line.substr(pos + 1, _pos - pos - 1);
        int __pos = fileName_.find('?');
        if (__pos >= 0) {
            fileName_ = fileName_.substr(0, __pos);
        }
        // default
        fileName_ = "index.html";
    }
    pos = _pos;

    // HTTP 版本号
    pos = request_line.find("/", pos);
    if (pos < 0) {
        return PARSE_URI_ERROR;
    } 
    if (request_line.size() - pos <= 3) {
        return PARSE_URI_ERROR;
    } 
    
    string ver = request_line.substr(pos + 1, 3);
    if (ver == "1.0"){
        HTTPversion_ = HTTP_10;
    }else if (ver == "1.1"){
        HTTPversion_ = HTTP_11;
    }else{
        return PARSE_URI_ERROR;
    }

    return PARSE_URI_SUCCESS;
}

int RequestData::ParseHeaders() {
    string &str = content_;

    int key_start = -1, key_end = -1, value_start = -1, value_end = -1;
    int now_read_line_begin = 0;

    bool Finish = false;

    for (int i = 0; i < str.size() && !Finish; ++i) {
        switch (hState_) {
            case H_START: {
                // 跳过空格
                if (str[i] == '\n' || str[i] == '\r'){
                    break;
                }
                key_start = i;
                now_read_line_begin = i;

                hState_ = H_KEY;
                break;
            }

            case H_KEY: {
                if (str[i] == '\n' || str[i] == '\r'){
                    return PARSE_HEADER_ERROR;
                }

                if (str[i] == ':') {
                    key_end = i;
        
                    hState_ = H_COLON;
                } 
                break;
            }

            case H_COLON: {
                if (str[i] != ' ') {
                    return PARSE_HEADER_ERROR;
                } 
                hState_ = H_SPACES_AFTER_COLON;
                break;
            }

            case H_SPACES_AFTER_COLON: {
                value_start = i;
                hState_ = H_VALUE;
                break;
            }

            case H_VALUE: {
                if (i - value_start > 255){
                    return PARSE_HEADER_ERROR;
                }
                if (str[i] == '\r') {
                    value_end = i;
                    hState_ = H_CR;
                } 
                break;
            }

            case H_CR: {
                if (str[i] != '\n') {
                    return PARSE_HEADER_ERROR;
                }
                if (key_end - key_start <= 0 || value_end - value_start <= 0){
                    return PARSE_HEADER_ERROR;
                }

                string key(str.begin() + key_start, str.begin() + key_end);
                string value(str.begin() + value_start, str.begin() + value_end);
                headers_[key] = value;

                now_read_line_begin = i;
                hState_ = H_LF;
                break;
            }

            case H_LF: {
                if (str[i] == '\r') {
                    hState_ = H_END_CR;
                } else {
                    key_start = i;
                    hState_ = H_KEY;
                }
                break;
            }

            case H_END_CR: {
                if (str[i] != '\n') {
                    return PARSE_HEADER_ERROR;
                }

                hState_ = H_END_LF;
                break;
            }

            case H_END_LF: {
                Finish = true;
                key_start = i;
                now_read_line_begin = i;
                break;
            }
        }
    }

    str = str.substr(now_read_line_begin); //去除已经分析的片段

    if (hState_ == H_END_LF) {
        return PARSE_HEADER_SUCCESS;
    }
    return PARSE_HEADER_AGAIN; //否则还需要再读数据
}

int RequestData::AnalysisRequest()
{
    if (method_ == METHOD_INVALID){
        return ANALYSIS_ERROR;
    }
    string header;
    header += string("HTTP/1.1 200 OK\r\n");
    if(headers_.find("Connection") != headers_.end() && headers_["Connection"] == "keep-alive"){
        keepAlive_ = true;
        header += string("Connection: keep-alive\r\n") + "Keep-Alive: timeout=" + to_string(5 * 60 * 1000) + "\r\n";
    }

    if (method_ == METHOD_POST){
        // post 解析传送过来的png
        int length = stoi(headers_["Content-length"]);
        vector<char> data(inBuffer_.begin(), inBuffer_.begin() + length);

        // Mat src = imdecode(data, CV_LOAD_IMAGE_ANYDEPTH|CV_LOAD_IMAGE_ANYCOLOR);
        // imwrite("receive.bmp", src);

        // Mat res = stitch(src);
        // vector<uchar> data_encode;
        // imencode(".png", res, data_encode);
        // header += string("Content-length: ") + to_string(data_encode.size()) + "\r\n\r\n";

        // outBuffer += header + string(data_encode.begin(), data_encode.end());
        outBuffer_ += header;

        inBuffer_ = inBuffer_.substr(length);
    }
    
    if (method_ == METHOD_GET){
        string filetype = MimeType::getMime("default");;

        int dot_pos = fileName_.find('.');
        if (dot_pos > 0){
            filetype = MimeType::getMime(fileName_.substr(dot_pos));
        }

        struct stat sbuf;
        if (stat(fileName_.c_str(), &sbuf) < 0){
            header.clear();
            return ANALYSIS_ERROR;
        }

        header += "Content-type: " + filetype + "\r\n";
        header += "Content-length: " + to_string(sbuf.st_size) + "\r\n";
        header += "\r\n";
        outBuffer_ += header;

        int src_fd = open(fileName_.c_str(), O_RDONLY, 0);
        char *src_addr = static_cast<char*>(mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, src_fd, 0));
        close(src_fd);

        outBuffer_ += src_addr;
        munmap(src_addr, sbuf.st_size);
    }

    if(!outBuffer_.empty()){
        channel_->EnableWriting();
    }

    return ANALYSIS_SUCCESS;
}

void RequestData::HandleError(int fd, int err_num, string short_msg) {
    short_msg = " " + short_msg;
    char send_buff[MAX_BUFF];
    string body_buff, header_buff;
    body_buff += "<html><title>TKeed Error</title>";
    body_buff += "<body bgcolor=\"ffffff\">";
    body_buff += to_string(err_num) + short_msg;
    body_buff += "<hr><em> LinYa's Web Server</em>\n</body></html>";

    header_buff += "HTTP/1.1 " + to_string(err_num) + short_msg + "\r\n";
    header_buff += "Content-type: text/html\r\n";
    header_buff += "Connection: close\r\n";
    header_buff += "Content-Length: " + to_string(body_buff.size()) + "\r\n";
    header_buff += "\r\n";
    sprintf(send_buff, "%s", header_buff.c_str());
    writen(fd, send_buff, strlen(send_buff));
    sprintf(send_buff, "%s", body_buff.c_str());
    writen(fd, send_buff, strlen(send_buff));

    delete this;
}